/*
 * ESPRESSIF MIT License
 *
 * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
 *
 * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
 * it is free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
 * to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include "ets_sys.h"
#include "osapi.h"
#include "at_custom.h"
#include "user_interface.h"
#include <string.h>
#include <stdio.h>

#if ((SPI_FLASH_SIZE_MAP == 0) || (SPI_FLASH_SIZE_MAP == 1))
#error "The flash map is not supported"
#elif (SPI_FLASH_SIZE_MAP == 2)
#define SYSTEM_PARTITION_OTA_SIZE							0x73000     //<460KB
#define SYSTEM_PARTITION_OTA_2_ADDR							0x81000
#define SYSTEM_PARTITION_RF_CAL_ADDR						0xfb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR						0xfc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR				0xfd000
#define SYSTEM_PARTITION_AT_PARAMETER_ADDR					0xf4000
#define SYSTEM_PARTITION_SSL_CLIENT_CERT_PRIVKEY_ADDR		0xf7000
#define SYSTEM_PARTITION_SSL_CLIENT_CA_ADDR					0xf8000
#define SYSTEM_PARTITION_WPA2_ENTERPRISE_CERT_PRIVKEY_ADDR	0xf9000
#define SYSTEM_PARTITION_WPA2_ENTERPRISE_CA_ADDR			0xfa000
#elif (SPI_FLASH_SIZE_MAP == 3)
#error "The flash map is not supported"
#elif (SPI_FLASH_SIZE_MAP == 4)
#error "The flash map is not supported"
#elif (SPI_FLASH_SIZE_MAP == 5)
#define SYSTEM_PARTITION_OTA_SIZE							0xE0000
#define SYSTEM_PARTITION_OTA_2_ADDR							0x101000
#define SYSTEM_PARTITION_RF_CAL_ADDR						0x1fb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR						0x1fc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR				0x1fd000
#define SYSTEM_PARTITION_AT_PARAMETER_ADDR					0xfd000
#define SYSTEM_PARTITION_SSL_CLIENT_CERT_PRIVKEY_ADDR		0xfc000
#define SYSTEM_PARTITION_SSL_CLIENT_CA_ADDR					0xfb000
#define SYSTEM_PARTITION_WPA2_ENTERPRISE_CERT_PRIVKEY_ADDR	0xfa000
#define SYSTEM_PARTITION_WPA2_ENTERPRISE_CA_ADDR			0xf9000
#elif (SPI_FLASH_SIZE_MAP == 6)
#define SYSTEM_PARTITION_OTA_SIZE							0xE0000     //<896KB
#define SYSTEM_PARTITION_OTA_2_ADDR							0x101000
#define SYSTEM_PARTITION_RF_CAL_ADDR						0x3fb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR						0x3fc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR				0x3fd000
#define SYSTEM_PARTITION_AT_PARAMETER_ADDR					0xfd000
#define SYSTEM_PARTITION_SSL_CLIENT_CERT_PRIVKEY_ADDR		0xfc000
#define SYSTEM_PARTITION_SSL_CLIENT_CA_ADDR					0xfb000
#define SYSTEM_PARTITION_WPA2_ENTERPRISE_CERT_PRIVKEY_ADDR	0xfa000
#define SYSTEM_PARTITION_WPA2_ENTERPRISE_CA_ADDR			0xf9000
#else
#error "The flash map is not supported"
#endif

#ifdef CONFIG_ENABLE_IRAM_MEMORY
uint32 user_iram_memory_is_enabled(void)
{
	return CONFIG_ENABLE_IRAM_MEMORY;
}
#endif

// test :AT+TEST=1,"abc"<,3>
void ICACHE_FLASH_ATTR
at_setupCmdTest(uint8_t id, char *pPara) {
	pPara += 1;

	int count = 0;
	int len = strlen(pPara);
	int idax1 = 0;
	int idax2 = 0;
	int idax3 = 0;

	for (int idax = 0; idax < len; idax++) {

		if (pPara[idax] == '/') {
			count++;

			if (count == 2) {
				idax1 = idax;
			}

			if (count == 3) {
				idax2 = idax;
			}
		}

		if (pPara[idax] == '.') {
			if (pPara[idax + 1] == 'b') {
				if (pPara[idax + 2] == 'i') {
					if (pPara[idax + 3] == 'n') {
						idax3 = idax + 3;
					}
				}
			}
		}
	}

	if (count < 3 || !((idax1 < idax2) && (idax2 < idax3))||(strstr(pPara,"https://")==NULL&&strstr(pPara,"HTTPS://")==NULL)) {
		at_response_error();
		return;
	}
	uint8_t dat1[64] = { 0 };
	memcpy(dat1, pPara + idax1 + 1, idax2 - idax1 - 1);
	uint8_t dat2[64] = { 0 };
	memcpy(dat2, pPara + idax2, idax3 - idax2 + 1);
//	os_sprintf(dat1, "%s\r\n", dat1);
//	os_sprintf(dat2, "%s\r\n", dat2);
//	at_port_print(dat1);
//	at_port_print(dat2);

	extern void ICACHE_FLASH_ATTR update_firmware(uint8_t *url1, uint8_t *url2);
	update_firmware(dat1, dat2);

//	at_response_ok();
}

void ICACHE_FLASH_ATTR
at_testCmdTest(uint8_t id) {
//	at_port_print_irom_str("at_testCmdTest\r\n");
//	at_response_ok();
	at_response_error();
}

void ICACHE_FLASH_ATTR
at_queryCmdTest(uint8_t id) {
//	at_port_print_irom_str("at_queryCmdTest\r\n");
//	at_response_ok();
	at_response_error();
}

void ICACHE_FLASH_ATTR
at_exeCmdTest(uint8_t id) {
//	at_port_print_irom_str("at_exeCmdTest\r\n");
//	at_response_ok();
	at_response_error();
}

extern void at_exeCmdCiupdate(uint8_t id);
at_funcationType at_custom_cmd[] = { { "+TEST", 5, at_testCmdTest,
		at_queryCmdTest, at_setupCmdTest, at_exeCmdTest }, { "+FOTA", 5,
		at_testCmdTest, at_queryCmdTest, at_setupCmdTest, at_exeCmdTest },
#ifdef AT_UPGRADE_SUPPORT
		{	"+CIUPDATE", 9, NULL, NULL, NULL, at_exeCmdCiupdate}
#endif
	};

static const partition_item_t at_partition_table[] =
		{ { SYSTEM_PARTITION_BOOTLOADER, 0x0, 0x1000 }, {
				SYSTEM_PARTITION_OTA_1, 0x1000, SYSTEM_PARTITION_OTA_SIZE }, {
				SYSTEM_PARTITION_OTA_2, SYSTEM_PARTITION_OTA_2_ADDR,
				SYSTEM_PARTITION_OTA_SIZE }, { SYSTEM_PARTITION_RF_CAL,
				SYSTEM_PARTITION_RF_CAL_ADDR, 0x1000 }, {
				SYSTEM_PARTITION_PHY_DATA, SYSTEM_PARTITION_PHY_DATA_ADDR,
				0x1000 }, { SYSTEM_PARTITION_SYSTEM_PARAMETER,
				SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR, 0x3000 }, {
				SYSTEM_PARTITION_AT_PARAMETER,
				SYSTEM_PARTITION_AT_PARAMETER_ADDR, 0x3000 }, {
				SYSTEM_PARTITION_SSL_CLIENT_CERT_PRIVKEY,
				SYSTEM_PARTITION_SSL_CLIENT_CERT_PRIVKEY_ADDR, 0x1000 }, {
				SYSTEM_PARTITION_SSL_CLIENT_CA,
				SYSTEM_PARTITION_SSL_CLIENT_CA_ADDR, 0x1000 },
#ifdef CONFIG_AT_WPA2_ENTERPRISE_COMMAND_ENABLE
		{	SYSTEM_PARTITION_WPA2_ENTERPRISE_CERT_PRIVKEY, SYSTEM_PARTITION_WPA2_ENTERPRISE_CERT_PRIVKEY_ADDR, 0x1000},
		{	SYSTEM_PARTITION_WPA2_ENTERPRISE_CA, SYSTEM_PARTITION_WPA2_ENTERPRISE_CA_ADDR, 0x1000},
#endif
	};

void ICACHE_FLASH_ATTR user_pre_init(void) {
	if (!system_partition_table_regist(at_partition_table,
			sizeof(at_partition_table) / sizeof(at_partition_table[0]),
			SPI_FLASH_SIZE_MAP)) {
		os_printf("system_partition_table_regist fail\r\n");
	}
}

void ICACHE_FLASH_ATTR
user_init(void) {

	struct softap_config apConfig = { 0 };
	char buf1[32] = { 0 };
	char add_buf[6] = { 0 };
	wifi_softap_get_config(&apConfig);
	wifi_get_macaddr(SOFTAP_IF, add_buf);
	os_sprintf(buf1, "AI_%02X%02X%02X\r\n", add_buf[3], add_buf[4], add_buf[5]);
	os_strcpy(apConfig.ssid, buf1);
	wifi_softap_set_config(&apConfig);

	char buf[128] = { 0 };
	at_customLinkMax = 5;
	at_init();
#ifdef ESP_AT_FW_VERSION
	if ((ESP_AT_FW_VERSION != NULL) && (os_strlen(ESP_AT_FW_VERSION) < 64)) {
		os_sprintf(buf,"compile time:"__DATE__" "__TIME__"\r\n"ESP_AT_FW_VERSION);
	} else {
		os_sprintf(buf,"compile time:"__DATE__" "__TIME__);
	}
#else
	os_sprintf(buf, "compile time:"__DATE__" "__TIME__);
#endif
	at_set_custom_info(buf);

	at_port_print("\r\nAi-Thinker Technology Co. Ltd.\r\n");
	at_port_print_irom_str("\r\nready\r\n");
	at_cmd_array_regist(&at_custom_cmd[0],
			sizeof(at_custom_cmd) / sizeof(at_custom_cmd[0]));
#ifdef CONFIG_AT_SMARTCONFIG_COMMAND_ENABLE
	at_cmd_enable_smartconfig();
#endif
#ifdef CONFIG_AT_WPA2_ENTERPRISE_COMMAND_ENABLE
	at_cmd_enable_wpa2_enterprise();
#endif
}
